`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/12/28 19:28:17
// Design Name: 
// Module Name: cordic
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module cordic(
input  logic        clk,
input  logic        rst_n,
input  logic        start,
input  logic [31:0] theta,               //0<theta<90
output logic [31:0] v_cos,
output logic [31:0] v_sin,
output logic        done
    );
/*
0 2949120.0
1 1740967.0
2 919879.0
3 466945.0
4 234379.0
5 117304.0
6 58666.0
7 29335.0
8 14668.0
9 7334.0
10 3667.0
11 1833.0
12 917.0
13 458.0
14 229.0
15 115.0
*/
logic signed [31:0] angle_lut [16-1:0];
assign angle_lut[0] = 2949120;
assign angle_lut[1] = 1740967;
assign angle_lut[2] = 919879;
assign angle_lut[3] = 466945;
assign angle_lut[4] = 234379;
assign angle_lut[5] = 117304;
assign angle_lut[6] = 58666;
assign angle_lut[7] = 29335;
assign angle_lut[8] = 14668;
assign angle_lut[9] = 7334;
assign angle_lut[10] = 3667;
assign angle_lut[11] = 1833;
assign angle_lut[12] = 917;
assign angle_lut[13] = 458;
assign angle_lut[14] = 229;
assign angle_lut[15] = 115;
//
logic signed [31:0] x;
logic signed [31:0] y;
logic signed [31:0] z;
logic signed [31:0] k;
logic [3:0]         cnt;
logic               busy;
logic signed [63:0] mult1;
logic signed [63:0] mult2;

assign k = 39797;
//
always_ff@(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        cnt <= 'd0;
    end
    else if(busy) begin
        cnt <= cnt + 1'b1;
    end
    else if(start) begin
        cnt <= 'd0;
    end
end
always_ff@(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        busy <= 1'b0;
    end
    else if(start) begin
        busy <= 1'b1;
    end
    else if(busy && cnt == 16 - 1) begin
        busy <= 1'b0;
    end
end
always_ff@(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        done <= 1'b0;
    end
    else if(busy && cnt == 16 - 1) begin
        done <= 1'b1;
    end
    else begin
        done <= 1'b0;
    end
end
//x,y,z
always_ff@(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        x <= 'd0;
        y <= 'd0;
        z <= 'd0;
    end
    else if(start) begin
        x <= (32'd1 << 16);
        y <= 32'd0;
        z <= (theta << 16);
    end
    else if(busy) begin
        if(z[31] == 1'b1) begin
            x <= x + ($signed(y) >>> cnt);
            y <= y - ($signed(x) >>> cnt);
            z <= z + angle_lut[cnt];
        end
        else begin
            x <= x - ($signed(y) >>> cnt);
            y <= y + ($signed(x) >>> cnt);
            z <= z - angle_lut[cnt];
        end
    end
end
//
assign mult1  = $signed(x) * $signed(k);
assign mult2  = $signed(y) * $signed(k);
assign v_cos  = $signed(mult1) >>> 16;
assign v_sin  = $signed(mult2) >>> 16;
endmodule
